﻿

using Microsoft.Extensions.Hosting;
using System;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;

namespace Simple.Service;

public class ServiceHelper
{
    /// <summary>
    /// 控制台运行 支持多个一起运行
    /// </summary>
    /// <param name="serviceModule"></param>
    public static void RunAsConsole(IServiceModule[] serviceModules, string[] args)
    {
        var host = Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostContext, config) =>
                {
                    foreach (var serviceModule in serviceModules)
                    {
                        Console.WriteLine($"配置【{serviceModule.serviceOptions.name}】管道");
                        serviceModule.ConfigApp(hostContext, config);
                    }
                })
                .ConfigureServices(service =>
                {
                    foreach (var serviceModule in serviceModules)
                    {
                        Console.WriteLine($"配置【{serviceModule.serviceOptions.name}】服务");
                        serviceModule.ConfigService(service);
                    }
                })
                .Build();

        host.Run();
    }
    /// <summary>
    /// 服务运行 只支持单个
    /// yourapp.exe start // 安装并启动服务
    /// yourapp.exe stop // 停止并删除服务
    /// yourapp.exe logs // 控制台输出服务的日志
    /// yourapp.exe logs filter="key words" // 控制台输出服务的日志
    /// </summary>
    /// <param name="serviceModule"></param>
    public static void RunAsService(IServiceModule serviceModule, string[] args)
    {
        WriteServiceXml(serviceModule, args);
        Console.WriteLine("请选择要进行的操作:");
        Console.WriteLine("----->0.直接运行");
        Console.WriteLine("----->1.注册服务");
        Console.WriteLine("----->2.启动服务");
        Console.WriteLine("----->3.重启服务");
        Console.WriteLine("----->4.停止服务");
        Console.WriteLine("----->5.刷新服务");
        Console.WriteLine("----->6.服务状态查看");
        Console.WriteLine("----->7.卸载服务");
        var commandType = Console.ReadLine();

        if(commandDic.TryGetValue(commandType, out var command))
        {
            RunCMD($@"Winsw.exe {command} Winsw.xml", out string message);
            Console.WriteLine(message);
            Console.ReadKey();
        }
        else
        {
            RunAsConsole(new IServiceModule[] { serviceModule }, args);
            Console.ReadKey();
        }
    }

    static readonly Dictionary<string, string> commandDic = new()
    {
        {"1","install" },{"2","start" },{"3","restart" },{"4","stop" },{"5","refresh" },{"6","status" },{"7","uninstall" }
    };

    static void WriteServiceXml(IServiceModule serviceModule, string[] args)
    {
        Console.WriteLine("正在生成服务配置文件Winsw.xml");
        if (File.Exists("Winsw.xml"))
        {
            Console.WriteLine("检测到服务配置文件Winsw.xml已生成，跳过");
            return;
        }

        serviceModule.serviceOptions.executable =Process.GetCurrentProcess().MainModule?.ModuleName;

        var xml =
$@"<service>
    <id>{serviceModule.serviceOptions.id}</id>
    <name>{serviceModule.serviceOptions.name}</name>
    <description>{serviceModule.serviceOptions.description}</description>
    <executable>{serviceModule.serviceOptions.executable}</executable>
    <arguments>{serviceModule.serviceOptions.arguments}</arguments>
    <logpath>%BASE%\logs</logpath>
    <log mode=""roll-by-time"">
      <pattern>yyyyMMdd</pattern>
    </log>
</service>
";
        File.WriteAllText("Winsw.xml", xml);
        Console.WriteLine("已生成服务配置文件Winsw.xml");
    }

    /// <summary>设置服务启动类型（CMD）</summary> 
    /// <param name="command">命令名称</param>
    /// <param name="message">设置失败时的原因</param>
    /// <returns>true：执行未报错</returns>
    static Boolean RunCMD(String command, out String message)
    {
        ProcessStartInfo startInfo = new ProcessStartInfo()
        {
            FileName = @"C:\Windows\System32\cmd.exe",
            WindowStyle = ProcessWindowStyle.Hidden,
            CreateNoWindow = true,
            UseShellExecute = false,
            RedirectStandardError = true,
            RedirectStandardInput = true,
            RedirectStandardOutput = true
        };
        Boolean result;
        Process process = new Process() { StartInfo = startInfo };

        try
        {
            process.Start();
            process.StandardInput.WriteLine(command);
            process.StandardInput.WriteLine("exit");
            Thread.Sleep(3000);
            message = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            result = true;

        }
        catch (Exception ex)
        {
            result = false;
            message = ex.Message + Environment.NewLine + ex.GetType().ToString();

        }
        finally
        {
            process.Close();
        }
        return result;
    }
}